#include "gpio.h"
void gpio_init(GPIO_Type* GPIOx, uint8_t Pin, gpio_config_type* config)
{
    if(config->direction == gpio_input)
    {
        GPIOx->GDIR &= ~(0x01 << Pin);
    }
    else if(config->direction == gpio_output)
    {
        GPIOx->GDIR |= (0x01 << Pin);
        gpio_pin_write(GPIOx, Pin, config->output);
    }

    gpio_int_config(GPIOx, Pin, config->Intmod);
}

void gpio_pin_write(GPIO_Type* GPIOx, uint8_t Pin, uint8_t value)
{
    if(value == 0)
    {
        GPIOx->DR &= ~(0x01 << Pin);
    }
    else if(value == 1)
    {
        GPIOx->DR |= (0x01 << Pin);
    }
}

int gpio_pin_read(GPIO_Type* GPIOx, uint8_t Pin)
{
    //return (GPIOx->DR & (0x01 << Pin)) != 0;
    return ((GPIOx->DR >> Pin) & 0x01);
}

void gpio_int_config(GPIO_Type* GPIOx, uint8_t Pin, gpio_interrupt_type Intmod)
{
    volatile unsigned int* reg;
    unsigned int irc_pin = Pin;

    GPIOx->EDGE_SEL &= ~(0x1 << Pin);

    if(Pin < 16)
    {
        reg = &(GPIOx->ICR1);
    }
    else
    {
        reg = &(GPIOx->ICR2);
        irc_pin -= 16;
    }

    switch (Intmod)
    {
    case gpio_lowIntmode:
        *reg &= ~(0x3 << (irc_pin * 2));
        break;
    case gpio_highIntmode:
        *reg &= ~(0x3 << (irc_pin * 2));
        *reg |= (0x1 << (irc_pin * 2));
        break;
    case gpio_risingIntmode:
        *reg &= ~(0x3 << (irc_pin * 2));
        *reg |= (0x2 << (irc_pin * 2));
        break;
    case gpio_fallingIntmode:
        *reg &= ~(0x3 << (irc_pin * 2));
        *reg |= (0x3 << (irc_pin * 2));
        break;
    case gpio_risingOrfallingIntmode:
        GPIOx->EDGE_SEL |= (0x1 << Pin);
        break;
    default:
        break;
    }
}

void gpio_enableint(GPIO_Type* GPIOx, uint8_t Pin)
{
    GPIOx->IMR |= (1 << Pin);
}

void gpio_disableint(GPIO_Type* GPIOx, uint8_t Pin)
{
    GPIOx->IMR &= ~(1 << Pin);
}

void gpio_clearflag(GPIO_Type* GPIOx, uint8_t Pin)
{
    GPIOx->ISR |= (1 << Pin);
}